﻿using System;
using System.IO;
using System.Net;
using System.Xml;

namespace EpubSqueaker
{
	class DtdResolver : XmlResolver
	{
		protected ICredentials credentials;

		public override ICredentials Credentials
		{
			set
			{
				credentials = value;
			}
		}

		public override Uri ResolveUri(Uri baseUri, String relativeUri)
		{
			if (relativeUri == null)
				throw new ArgumentNullException("relativeUri");

			switch (relativeUri.ToUpperInvariant())
			{
				case "-//W3C//DTD XHTML 1.1//EN":
					return new Uri("http://www.w3.org/tr/xhtml11/DTD/xhtml11.dtd");
				case "-//NISO//DTD NCX 2005-1//EN":
					return new Uri("http://www.daisy.org/z3986/2005/ncx-2005-1.dtd");
			}

			return base.ResolveUri(baseUri,relativeUri);
		}

		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
		override public object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
		{
			if ((absoluteUri == null) || (absoluteUri.AbsoluteUri == null))
				throw new ArgumentNullException("absoluteUri");

			// Catch bad entities that should never have been considered URLs.
			if (absoluteUri.AbsoluteUri.ToUpperInvariant().Contains("-//W3C//"))
				return null;

			switch (absoluteUri.AbsoluteUri.ToUpperInvariant())
			{
				#region XHTML 1.1
				case "HTTP://WWW.W3.ORG/TR/XHTML11/DTD/XHTML11.DTD":
					return new MemoryStream(DtdXhtml11.xhtml11);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-INLSTYLE-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_inlstyle_1);
				case "HTTP://WWW.W3.ORG/TR/XHTML11/DTD/XHTML-DATATYPES-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_datatypes_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-FRAMEWORK-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_framework_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-QNAME-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_qname_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-EVENTS-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_events_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-ATTRIBS-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_attribs_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML11-MODEL-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml11_model_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-CHARENT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_charent_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-LAT1.ENT":
					return new MemoryStream(DtdXhtml11.xhtml_lat1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-SYMBOL.ENT":
					return new MemoryStream(DtdXhtml11.xhtml_symbol);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-SPECIAL.ENT":
					return new MemoryStream(DtdXhtml11.xhtml_special);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-TEXT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_text_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-INLSTRUCT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_inlstruct_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-INLPHRAS-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_inlphras_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-BLKSTRUCT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_blkstruct_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-BLKPHRAS-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_blkphras_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-HYPERTEXT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_hypertext_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-LIST-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_list_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-EDIT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_edit_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-BDO-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_bdo_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-RUBY-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_ruby_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-PRES-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_pres_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-INLPRES-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_inlpres_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-BLKPRES-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_blkpres_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-LINK-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_link_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-META-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_meta_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-BASE-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_base_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-SCRIPT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_script_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-STYLE-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_style_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-IMAGE-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_image_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-CSISMAP-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_csismap_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-SSISMAP-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_ssismap_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-PARAM-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_param_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-OBJECT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_object_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-TABLE-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_table_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-FORM-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_form_1);
				case "HTTP://WWW.W3.ORG/MARKUP/DTD/XHTML-STRUCT-1.MOD":
					return new MemoryStream(DtdXhtml11.xhtml_struct_1);
				#endregion

				#region NCX
				case "HTTP://WWW.DAISY.ORG/Z3986/2005/NCX-2005-1.DTD":
					return new MemoryStream(DtdNcx.ncx_2005_1);
				#endregion
			}

			// Fall back on grabbing it from the web.
			System.Diagnostics.Debug.WriteLine("Could not find URL: {0}", absoluteUri);
			XmlUrlResolver xur = new XmlUrlResolver();
			xur.Credentials = credentials;
			try
			{
				return xur.GetEntity(absoluteUri, role, ofObjectToReturn);
			}
			catch (WebException ex)
			{
				var response = ex.Response as HttpWebResponse;
				switch (response.StatusCode)
				{
					case HttpStatusCode.NotFound:
					case HttpStatusCode.Forbidden:
						return null;
				}
				throw;
			}
		}
	}
}
